﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UMC.Data;
using UMC.Net;

namespace UMC.Host
{

    class HttpContext : UMC.Net.NetContext
    {
        public override StringValue Scheme => this._request._scheme;
        public override void AddHeader(HeadValue head)
        {
            this._response.AddHeader(head);
        }

        public override NetLoger Loger => _response.loger;
        public override string Server => HttpServier.Server;
        HttpRequest _request;
        HttpResponse _response;
        public override long? ContentLength { get => _request.ContentLength; set => _response.ContentLength = value; }
        public override void AppendCookie(string name, string value)
        {
            this.AppendCookie(name, value, "/");

        }
        public override void OutputHeaded(Action action)
        {
            _response.Headed = action;
        }
        public override void AddHeader(StringValue name, String value)
        {
            _response.AddHeader(new HeadValue(name, _request.Memory.Rent(value)));
        }
        public override void AppendCookie(string name, string value, string path)
        {
            if (UMC.Web.WebServlet.SessionCookieName.Span.SequenceEqual(name.UTF8()))
            {

                _response.AddHeader(new HeadValue(StringValue.SetCookie, _request.Memory.Rent($"{name}={value}; Expires={DateTime.Now.AddYears(10):r}; Path={path}")));

            }
            else
            {
                _response.AddHeader(new HeadValue(StringValue.SetCookie, _request.Memory.Rent($"{name}={value}; Path={path}")));
            }
        }
        public override void Redirect(StringValue url)
        {
            this._response.Redirect(url);
        }
        public override void RewriteUrl(string pathAndQuery)
        {
            this._request.RewriteUrl(new StringValue(pathAndQuery));
            _QueryString = null;
        }
        public override bool IsWebSocket => _request.IsWebSocket;
        Net.TextWriter writer;

        public HttpContext(HttpRequest request, HttpResponse response)
        {
            this._request = request;
            this._response = response;
            writer = new Net.TextWriter(response.OutputStream.Write);
        }
        public override void ReadAsData(NetWriteData readData)
        {
            if (_request.ContentLength > 0 && _request.IsMimeFinish == false)
            {
                if (aseSynchronousIOEnd == false)
                {
                    aseSynchronousIOEnd = true;
                }
            }
            this._request.ReadAsData(readData);
        }
        bool aseSynchronousIOEnd;
        public override void UseSynchronousIO()
        {
            aseSynchronousIOEnd = true;
        }
        public override void OutputFinish()
        {

            if (aseSynchronousIOEnd)
            {
                this.Output.Flush();
                if (_response.OutputFinish())
                {
                    _request._context.OutputFinish();
                }
                else
                {
                    _request._context.Dispose();
                }

                _request.Dispose();
            }

        }
        public override void Error(Exception ex)
        {

            this.Output.Flush();
            _response.OutputError(ex);
            _request._context.Dispose();
            _request.Dispose();

        }
        public override void ReadAsForm(Action<HeadValues> action)
        {
            if (_request.ContentLength > 0 && _request.IsMimeFinish == false)
            {
                if (aseSynchronousIOEnd == false)
                {
                    aseSynchronousIOEnd = true;// () => { };
                }
            }
            _request.ReadAsForm(action);
        }
        public void ProcessRequest(UMC.Net.INetHandler handler)
        {
            handler.ProcessRequest(this);
            if (this.IsWebSocket == false && aseSynchronousIOEnd == false)
            {
                this.Output.Flush();
                _response.OutputFinish();
                _request._context.OutputFinish();

                _request.Dispose();
            }


        }

        public override int StatusCode
        {
            get
            {
                return this._response.StatusCode;
            }
            set
            {
                this._response.StatusCode = value;
            }
        }
        public override void AddHeader(string name, string value)
        {
            this._response.AddHeader(name, value);
        }


        HeadValues _QueryString;
        public override HeadValues QueryString
        {
            get
            {
                if (_QueryString == null)
                {
                    if (this.Query.IsEmpty == false)
                    {
                        _QueryString = new HeadValues(true);
                        var s = Query;
                        var span = s.Span;
                        var size = span.Length;
                        StringValue key = StringValue.Empty;
                        int start = 1;
                        for (int i = 1; i < size; i++)
                        {
                            switch (span[i])
                            {
                                case 0x26:
                                    _QueryString.Add(new HeadValue(key, s.Slice(start, i - start)));

                                    start = i + 1;
                                    break;
                                case 0x3d:
                                    key = s.Slice(start, i - start);
                                    start = i + 1;
                                    break;
                            }
                        }
                        if (start < size)
                        {
                            _QueryString.Add(new HeadValue(key, s.Slice(start, size - start)));
                        }
                    }
                    else
                    {
                        _QueryString = new HeadValues();
                    }
                }
                return _QueryString;
            }
        }

        public override  UMC.Net.TextWriter Output
        {
            get
            {
                return this.writer;
            }
        }
        public override System.IO.Stream OutputStream
        {
            get
            {
                return this._response.OutputStream;
            }
        }
        // String _ContentType;
        public override StringValue ContentType
        {
            get
            {
                // if (_ContentType == null)
                // {
                return this._request.ContentType;//.Span.UTF8();
                // }
                // return _ContentType;//this._request.ContentType.UTF8();
            }
            set
            {
                this._response.ContentType = value;
            }
        }

        public override string UserHostAddress
        {
            get { return this._request.UserHostAddress; }
        }

        public override StringValue RawUrl
        {
            get { return _request.Second; }
        }

        public override StringValue UserAgent
        {
            get { return this._request.Headers.Get(StringValue.UserAgent.Span); }
        }
        public override Uri UrlReferrer
        {
            get
            {
                return _request.UrlReferrer;
            }
        }

        public override Uri Url
        {
            get { return _request.Url; }
        }

        public override void Redirect(string url)
        {
            this._response.Redirect(this.Memory.Rent(url));
        }

        public override ByteChunk Memory => _request.Memory;



        public override HttpMethod Method
        {
            get { return this._request.HttpMethod; }
        }

        public override StringValue Host => this._request._host;
        public override StringValue Path => _request.Path;
        public override StringValue Query => _request.Query;
        public override StringValue PathQuery => _request.PathQuery;

        public override HeadValues Headers => _request.Headers;

        public override HeadValues Cookies => _request.Cookies;

    }
}
